﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Steganograf.Controls
{
    public partial class Histogram : System.Windows.Forms.UserControl
    {
        public Histogram()
        {
            // This call is required by the Windows.Forms Form Designer.
            InitializeComponent();

            // TODO: Add any initialization after the InitializeComponent call

            this.Paint += new PaintEventHandler(HistogramaDesenat_Paint);
            this.Resize += new EventHandler(HistogramaDesenat_Resize);
        }
        
        private void HistogramaDesenat_Paint(object sender, PaintEventArgs e)
        {
            if (m_isDrawing)
            {
                Graphics g = e.Graphics;
                Pen myPen = new Pen(new SolidBrush(m_color), m_XUnit);
                int delta = (int)Math.Ceiling(m_values.Length * 0.0005); //we ommit some of the values to make the histogram readable

                //the width of the pen is given by the XUnit for the control
                for (int i = 0; i < m_values.Length; i+=delta)
                {
                    //drawing each line 
                    g.DrawLine(myPen,
                        new PointF(m_offset + (i * m_XUnit), this.Height - m_offset),
                        new PointF(m_offset + (i * m_XUnit), this.Height - m_offset - m_values[i] * m_YUnit));
                }

                //drawing the indexes for 0 and for the length of the array beeing plotted
                g.DrawString("0", m_font, new SolidBrush(m_color), new PointF(m_offset, this.Height - m_font.Height), System.Drawing.StringFormat.GenericDefault);
                g.DrawString((m_values.Length - 1).ToString(), m_font,
                    new SolidBrush(m_color),
                    new PointF(m_offset + (m_values.Length * m_XUnit) - g.MeasureString((m_values.Length - 1).ToString(), m_font).Width,
                    this.Height - m_font.Height),
                    System.Drawing.StringFormat.GenericDefault);

                //drawing a rectangle surrounding the control.
                g.DrawRectangle(new System.Drawing.Pen(new SolidBrush(Color.Black), 1), 0, 0, this.Width - 1, this.Height - 1);
            }

        }

        [Category("Histogram Options")]
        [Description("The distance from the margins for the histogram")]
        public int Offset
        {
            set
            {
                if (value > 0)
                    m_offset = value;
            }
            get
            {
                return m_offset;
            }
        }

        [Category("Histogram Options")]
        [Description("The color used within the control")]
        public Color DisplayColor
        {
            set
            {
                m_color = value;
            }
            get
            {
                return m_color;
            }
        }

        public void DrawHistogram(int[] Values)
        {
            m_values = Values;

            m_isDrawing = true;
            m_maxValue = getMax(m_values);

            ComputeXYUnitValues();

            this.Refresh();
        }

        public void DrawHistogram(Bitmap picture)
        {
            int[] myHistogram = new int[(picture.Size.Width-1) * (picture.Size.Height-1)];
            m_pictureHeight = picture.Height;
            m_pictureWidth = picture.Width;

            for (int i = 1; i < m_pictureWidth-1; i++)
                for (int j = 1; j < m_pictureHeight - 1; j++)
                {
                    Color currPixel = picture.GetPixel(i, j);

                    //x-1, y+1      x, y+1      x+1, y+1
                    //x-1, y        x, y        x+1, y
                    //x-1, y-1      x, y-1      x+1, y-1
                    int differences = 0;
                    for(int x = -1; x < 2; x++)
                        for (int y = -1; y < 2; y++)
                        {
                            if (x == 0 && y == 0) continue;
                            Color adjacentPixel = picture.GetPixel(i + x, j + y);
                            if (!Color.Equals(currPixel, adjacentPixel)) differences++;
                        }

                    myHistogram[(i - 1) * m_pictureHeight + j - 1] += differences;
                    // j = x % height + 1;
                    // i = (x - j + 1) / height + 1;
                }

            DrawHistogram(myHistogram);
        }

        public Dictionary<string, int> CountHistogramDifferences(int[] pValues)
        {
            Dictionary<string, int> result = new Dictionary<string, int>();

            if (pValues.Length != m_values.Length) return result;

            for (int i = 0; i < pValues.Length; i++)
                if (pValues[i] != m_values[i])
                {
                    int orig_j = i % m_pictureHeight + 1;
                    int orig_i = (i - orig_j + 1) / m_pictureHeight + 1;
                    result.Add(orig_i + "|" + orig_j, m_values[i] - pValues[i]);
                }                 
            
            return result;
        }

        private int getMax(int[] Vals)
        {
            if (m_isDrawing)
            {
                int max = 0;
                for (int i = 0; i < Vals.Length; i++)
                {
                    if (Vals[i] > max)
                        max = Vals[i];
                }
                return max;
            }
            return 1;
        }

        private void HistogramaDesenat_Resize(object sender, EventArgs e)
        {
            if (m_isDrawing)
            {
                ComputeXYUnitValues();
            }
            this.Refresh();
        }

        private void ComputeXYUnitValues()
        {
            m_YUnit = (float)(this.Height - (2 * m_offset)) / m_maxValue;
            m_XUnit = (float)(this.Width - (2 * m_offset)) / (m_values.Length - 1);
        }

        public int[] HistogramValues
        {
            get
            {
                return m_values;
            }
        }

        private int m_maxValue;
        private int[] m_values;
        private bool m_isDrawing;

        private float m_YUnit; //this gives the vertical unit used to scale our values
        private float m_XUnit; //this gives the horizontal unit used to scale our values
        private int m_offset = 20; //the offset, in pixels, from the control margins.

        private Color m_color = Color.Black;
        private Font m_font = new Font("Tahoma", 8);

        private int m_pictureHeight;
        private int m_pictureWidth;
    }
}
